#include "preHeader.h"
#include "ItemDef.h"

inst_item_prop::inst_item_prop(uint32 itemTypeID, uint32 itemCount)
: itemGuid(0)
, itemTypeID(itemTypeID)
, itemCount(itemCount)
, itemOwner(0)
, itemStatus(0)
{
}

template <typename Packer>
void save_inst_item_prop(const inst_item_prop& itemProp, Packer& packer)
{
	packer << itemProp.itemGuid << itemProp.itemTypeID << itemProp.itemCount
		<< itemProp.itemOwner << itemProp.itemStatus;
}

template <typename Unpacker>
void load_inst_item_prop(inst_item_prop& itemProp, Unpacker& unpacker)
{
	unpacker >> itemProp.itemGuid >> itemProp.itemTypeID >> itemProp.itemCount
		>> itemProp.itemOwner >> itemProp.itemStatus;
}

void inst_item_prop::Save(INetStream& pck) const
{
	save_inst_item_prop(*this, pck);
}

void inst_item_prop::Load(INetStream& pck)
{
	load_inst_item_prop(*this, pck);
}

void inst_item_prop::Save(TextPacker& packer) const
{
	save_inst_item_prop(*this, packer);
}

void inst_item_prop::Load(TextUnpacker& unpacker)
{
	load_inst_item_prop(*this, unpacker);
}

std::string inst_item_prop::Save() const
{
	TextPacker packer;
	Save(packer);
	return packer.str();
}

void inst_item_prop::Load(const char* data)
{
	TextUnpacker unpacker(data);
	Load(unpacker);
}

inst_item_prop NewItemProp4Owner(
	uint32 itemTypeID, uint32 itemCount, uint32 itemOwner)
{
	inst_item_prop itemProp(itemTypeID, itemCount);
	itemProp.itemOwner = itemOwner;
	return itemProp;
}

inst_item_prop NewItemProp4Flags(
	uint32 itemTypeID, uint32 itemCount, uint32 itemFlags)
{
	inst_item_prop itemProp(itemTypeID, itemCount);
	if (BIT_ISSET(itemFlags, (int)ItemFlag::Binding)) {
		itemProp.itemOwner = 1;
	}
	if (BIT_ISSET(itemFlags, (int)ItemFlag::Constant)) {
		BIT_SET(itemProp.itemStatus,
			(int)inst_item_prop::Status::Constant);
	}
	return itemProp;
}

std::vector<inst_item_prop> NewItemProps4ItemInfo(
	const std::vector<ItemInfo>& itemInfos)
{
	std::vector<inst_item_prop> itemProps;
	itemProps.reserve(itemInfos.size());
	for (auto& itemInfo : itemInfos) {
		itemProps.push_back({itemInfo.id, itemInfo.num});
	}
	return itemProps;
}

std::vector<inst_item_prop> NewItemProps4FItemInfo(
	const std::vector<FItemInfo>& itemInfos)
{
	std::vector<inst_item_prop> itemProps;
	itemProps.reserve(itemInfos.size());
	for (auto& itemInfo : itemInfos) {
		itemProps.push_back(NewItemProp4Flags(
			itemInfo.id, itemInfo.num, itemInfo.flags));
	}
	return itemProps;
}

struct InstEquipMultiSlot {
	int cls;
	size_t num;
};
const static InstEquipMultiSlot sInstEquipMultiSlotCfgs[]{
	{(int)ItemSubClass::Equip_Gloves, 2},
	{(int)ItemSubClass::Equip_Shoes, 2},
};

static std::pair<uint32, uint32> GetEquipSlotRange(
	const InstEquipMultiSlot cfgs[], size_t n, int cls, int offest)
{
	size_t extraNum = 0, availNum = 1;
	for (size_t i = 0; i < n; ++i) {
		auto& cfg = cfgs[i];
		if (cls < cfg.cls) {
			break;
		}
		if (cls == cfg.cls) {
			availNum = cfg.num;
			break;
		}
		extraNum += cfg.num - 1;
	}
	auto slotBegin = offest + cls + extraNum;
	return {uint32(slotBegin), uint32(slotBegin + availNum)};
}

bool IsItemProtoEquipSlotValid(const ItemPrototype* pItemProto, uint32 slot)
{
	if (slot != ItemSlotInvalid) {
		auto rst = ItemProto2EquipSlot(pItemProto);
		if (rst.first <= slot && slot < rst.second) {
			return true;
		}
	}
	return false;
}

std::pair<uint32, uint32> ItemProto2EquipSlot(const ItemPrototype* pItemProto)
{
	switch ((ItemClass)pItemProto->itemClass) {
	case ItemClass::Equip:
		return GetEquipSlotRange(
			sInstEquipMultiSlotCfgs, ARRAY_SIZE(sInstEquipMultiSlotCfgs),
			pItemProto->itemSubClass, -1);
	default:
		return {ItemSlotInvalid, ItemSlotInvalid};
	}
}
